/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package hw2;

import hw2.frame.MyFrame;
import java.awt.Color;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Stack;

/**
 *
 * @author Sanya
 */
public class Engine {

    private MyFrame frame;
    private ArrayList<Furniture> furnitures;
    private int[][] arr;
    private Stack<Furniture> moves;
    private Color[] color;

    public Engine(MyFrame frame) {
        this.frame = frame;
        furnitures = new ArrayList<Furniture>();
        moves = new Stack<>();
        arr = new int[10][20];
        color = new Color[5];
        init();
        //this.house.
    }

    private void init() {
        for (int i = 0; i < 10; i++) {
            for (int j = 0; j < 20; j++) {
                if (j > 10) {
                    if (i < 4) {
                        arr[i][j] = 2;//room2
                    } else {
                        arr[i][j] = 3;//room3
                    }
                } else {
                    arr[i][j] = 0;
                }
            }
        }
        //walls
        arr[0][10] = -1;
        frame.paintPanel(11, 1, 11, 1, Color.black, true);
        arr[3][10] = -1;
        arr[4][10] = -1;
        frame.paintPanel(11, 4, 11, 5, Color.black, true);
        arr[9][10] = -1;
        frame.paintPanel(11, 10, 11, 10, Color.black, true);
        //print
        for (int i = 0; i < 10; i++) {
            for (int j = 0; j < 20; j++) {
                System.out.format("%d,", arr[i][j]);
            }
            System.out.format("%n");
        }
        //color for each fur
        color[0] = Color.WHITE;
        color[1] = Color.GREEN;
        color[2] = Color.RED;
        color[3] = Color.YELLOW;
        color[4] = Color.BLUE;
    }

    public boolean checkMove(int sx, int sy, int ex, int ey, int tRoom, int myNum) {
        for (int i = sy - 1; i < ey; i++) {
            for (int j = sx - 1; j < ex; j++) {
                if ((tRoom == 2 && (arr[i][j] == 3 || arr[i][j] == myNum))
                        || (tRoom == 2 && (arr[i][j] == 2 || arr[i][j] == myNum))) {
                    continue;
                }
                return false;
            }
        }
        return true;
    }

    public boolean furnitureFits(Furniture furniture) {
        // Check if a furniture clashes with any other furniture in the house.
        boolean fits = true;

        for (Furniture fur : furnitures) {
            if (fur.isClashingWith(furniture)) {
                fits = false;
                break;
            }
        }

        return fits;
    }

    public void addFurniture(Furniture fur) throws Exception {
        // Add furniture only if it is not clashing.  
        if (this.furnitureFits(fur)) {
            furnitures.add(fur);
            fur.setNum(furnitures.size());
            frame.getErrorText().setText(String.format("Success! number of furnitures: %d ", furnitures.size()));
        } else {
            throw new Exception("Furniture does not fit!");
        }
        frame.paintPanel(fur.getInitSX(), fur.getInitSY(), fur.getInitEX(), fur.getInitEY(), color[fur.getNum()], true);
        frame.paintPanel(fur.getTargSX(), fur.getTargSY(), fur.getTargEX(), fur.getTargEY(), color[2*fur.getNum()], true);
    }

    public void paintFurniture(Furniture fur) {
        frame.paintPanel(fur.getCurrSX(), fur.getCurrSY(), fur.getCurrEX(), fur.getCurrEY(), color[fur.getNum()], true);
    }
    public void paintWhite(Furniture fur) {
        for(int i=0; i<100;i++){
            //wait
        }
        frame.paintPanel(fur.getCurrSX(), fur.getCurrSY(), fur.getCurrEX(), fur.getCurrEY(), color[0], true);
    }

    public boolean checkFurniture(Furniture fur) {
        return frame.paintPanel(fur.getCurrSX(), fur.getCurrSY(), fur.getCurrEX(), fur.getCurrEY(), color[fur.getNum()], false);
    }

    public void printToStack(Furniture fur){
        String s =fur.getStackMoves().pop().toString() + " Furniture=" + fur.getNum();
        System.out.format("%s  ", s);
        frame.getStackTextArea().append(s + "\n");
        
    }
    
    public LinkedList<Furniture> generateMoves(Furniture fur) throws Exception {
        LinkedList<Furniture> furnitureList = new LinkedList<Furniture>();
        boolean left=false, right=false, rotate=false, up=false, down=false;
        
        /* Move left/right */
        if (fur.getCurrSX() > fur.getTargSX()) {
            furnitureList.addFirst(fur.generateFurniture(Action.MOVE_LEFT));
            left = true;
        }
        else if (fur.getCurrEX() < fur.getTargEX()) {
            furnitureList.addFirst(fur.generateFurniture(Action.MOVE_RIGHT));
            right = true;
        }
        /* Rotate */
        if ((fur.getCurrEY() - fur.getCurrSY()) != (fur.getTargEY() - fur.getTargSY())) {
            rotate = true;
            if (right) {
                if (fur.canRotateR()) {
                    furnitureList.addFirst(fur.generateFurniture(Action.ROTATE_RIGHT));
                }
                if (fur.canRotateL()) {
                    furnitureList.addFirst(fur.generateFurniture(Action.ROTATE_LEFT));
                }
            }
            else {
                if (fur.canRotateL()) {
                    furnitureList.addFirst(fur.generateFurniture(Action.ROTATE_LEFT));
                }  
                if (fur.canRotateR()) {
                    furnitureList.addFirst(fur.generateFurniture(Action.ROTATE_RIGHT));
                }            
            }
        }
        /* Down */
        if (fur.getCurrEY() < fur.getTargEY()) {
            down = true;
            if (fur.canMoveUp()) {
                furnitureList.addFirst(fur.generateFurniture(Action.MOVE_UP));
            }
            if (fur.canMoveDown()) {
                furnitureList.addLast(fur.generateFurniture(Action.MOVE_DOWN));
            }
        }
        /* Up */
        if (fur.getCurrEY() > fur.getTargEY()) {
            up = true;
            if (fur.canMoveDown()) {
                furnitureList.addFirst(fur.generateFurniture(Action.MOVE_DOWN));
            }
            if (fur.canMoveUp()) {
                furnitureList.addLast(fur.generateFurniture(Action.MOVE_UP));
            }
        }
        
        /* Add optional moves */
        if (!up && !down) {
            if (fur.canMoveUp()) {
                furnitureList.addLast(fur.generateFurniture(Action.MOVE_UP));
            }
            if (fur.canMoveDown()) {
                furnitureList.addLast(fur.generateFurniture(Action.MOVE_DOWN));
            }
        }
        if (!right && !left) {
            if (fur.canMoveR()) {
                furnitureList.addLast(fur.generateFurniture(Action.MOVE_RIGHT));
            }
            if (fur.canMoveL()) {
                furnitureList.addLast(fur.generateFurniture(Action.MOVE_LEFT));
            }
        }
        if (!rotate) {
            if (fur.canRotateR()) {
                furnitureList.addLast(fur.generateFurniture(Action.ROTATE_RIGHT));
            }
            if (fur.canRotateL()) {
                furnitureList.addLast(fur.generateFurniture(Action.ROTATE_LEFT));
            }
        }
        
        return furnitureList;
    }
    
    public void update(StackOp stack_operation, Furniture fur, int fur_id) {
        switch (stack_operation) {
            case PUSH_PAINT:
                moves.push(fur);
                paintWhite(fur);
                paintFurniture(fur);
                //frame.getStackTextArea().append();
                break;
            case POP_PAINT:
                moves.pop();
                furnitures.set(fur_id, fur);
                paintWhite(fur);
                paintFurniture(fur);
                break;
            case PUSH_NO_PAINT:
                break;
            case POP_NO_PAINT:
                moves.pop();
                break;
        }
    }
    
    public boolean stripsGo(int step_count, Furniture current_fur, LinkedList<Furniture> moves, int fur_id) throws Exception {
        System.out.println("Step count: " + step_count);
        boolean result = false;
        LinkedList<Furniture> new_moves;
        int moves_count = moves.size();
        
        if (0 == moves.size() || 0 == step_count) {
            return result;
        }
        
        while (0 != moves.size() && !result) {
            if (moves_count < moves.size()) {
                update(StackOp.POP_NO_PAINT, null, fur_id);
            }
            
            furnitures.set(fur_id, moves.removeFirst());
            
            update(StackOp.PUSH_PAINT, furnitures.get(fur_id).generateFurniture(Action.NONE), fur_id);
            
            if (furnitures.get(fur_id).goalReached()) {
                result = true;
            }
            else {
                new_moves = generateMoves(furnitures.get(fur_id));
                result = stripsGo(step_count - 1, furnitures.get(fur_id), new_moves, fur_id);
            }
        }

        return result;
    }
    
    public void stripstart() throws Exception {
        
        for (int index = 0; index < furnitures.size(); index++) {
            update(StackOp.PUSH_PAINT, furnitures.get(index).generateFurniture(Action.NONE), index);
            LinkedList<Furniture> new_moves = generateMoves(furnitures.get(index));
            System.out.println("Result: " + stripsGo(20, furnitures.get(index), new_moves, index));
        }
    }
    
    public void start() throws Exception {
        stripstart();
        /*
        Furniture fur;
        for (int i = 0; i < furnitures.size(); i++) {
            fur = (Furniture) furnitures.get(i);
            goToDoor(fur);
            goThroughDoor(fur);
            goToInit(fur);
        }
        */
    }

    public void goToDoor(Furniture fur) {
        paintWhite(fur);
        if (fur.getCurrLenthX() < fur.getCurrLenthY()) {
            fur.rotateR();
            if (!checkFurniture(fur)) {
                fur.rotateL();
                fur.rotateL();
            }
            printToStack(fur);
        }
        paintFurniture(fur);
        if (fur.getTargetRoom() == 2) {//DOOR OF ROOMS 1,2
            leftRigthUpDown(fur, 12, 3);
        } else {//DOOR OF ROOMS 1,3
            leftRigthUpDown(fur, 12, 7);
        }
    }

    public void goThroughDoor(Furniture fur) {
        for (int i = fur.getCurrLenthX() + 1; i > 0; i--) {
            paintWhite(fur);
            fur.moveL();
            printToStack(fur);
            paintFurniture(fur);
        }
    }

    public void goToInit(Furniture fur) {
        while (fur.getCurrEX() - fur.getInitEX() > 0) {
            paintWhite(fur);
            fur.moveL();
            printToStack(fur);
            paintFurniture(fur);
        }
        while (fur.getCurrEX() - fur.getInitEX() < 0) {
            paintWhite(fur);
            fur.moveR();
            printToStack(fur);
            paintFurniture(fur);
        }
        while (fur.getCurrEY() - fur.getInitEY() > 0) {
            paintWhite(fur);
            fur.moveDown();
            printToStack(fur);
            paintFurniture(fur);
        }
        while (fur.getCurrEY() - fur.getInitEY() < 0) {
            paintWhite(fur);
            fur.moveUp();
            printToStack(fur);
            paintFurniture(fur);
        }
        System.out.format("CurrLenthX=%d, InitLenthX=%d,  %n", fur.getCurrLenthX(), Math.abs(fur.getInitSX() - fur.getInitEX()) + 1);
        if (fur.getCurrSX() != fur.getInitSX()) {
            paintWhite(fur);
                System.out.format("CurrLenthX=%d, InitLenthX=%d,  %n", fur.getCurrLenthX(), Math.abs(fur.getInitSX() - fur.getInitEX()) + 1);
                fur.rotateR();
                if (!checkFurniture(fur) || (fur.getCurrSX() != fur.getInitSX())) {
                    fur.rotateL();
                    fur.rotateL();
                }
            printToStack(fur);
            paintFurniture(fur);
        }
        fur.printM();
        System.out.format("CurrLenthX=%d, InitLenthX=%d,  %n", fur.getCurrLenthX(), Math.abs(fur.getInitSX() - fur.getInitEX()) + 1);
    }

    public void leftRigthUpDown(Furniture fur, int x, int y) {
        while (fur.getCurrEX() - x > 0) {
            paintWhite(fur);
            fur.moveL();
            printToStack(fur);
            paintFurniture(fur);
        }
        while (fur.getCurrEX() - x < 0) {
            paintWhite(fur);
            fur.moveR();
            printToStack(fur);
            paintFurniture(fur);
        }
        while (fur.getCurrEY() - y > 0) {
            paintWhite(fur);
            fur.moveDown();
            printToStack(fur);
            paintFurniture(fur);
        }
        while (fur.getCurrEY() - y < 0) {
            paintWhite(fur);
            fur.moveUp();
            printToStack(fur);
            paintFurniture(fur);
        }
    }
}
